#include "client_connection.h"
#include "connection.h"
#include "dl_protocol.h"
#include "jmsg.h"
#define HEART_BEAT_TIMER 0
#define RECONNECT_TIMER 1

struct DBConnectionCmd {
	int intArgs1;
	int intAgrs2;
	int intArgs3;
	void* dataArgs;	
};

static uint32_t uint32ToNetwork(uint32_t input) {
	uint32_t output = 0;
	unsigned char* buffer = (unsigned char*)&output;
	buffer[0] = (input >> 24) & 0xff;
	buffer[1] = (input >> 16) & 0xff;
	buffer[2] = (input >> 8) & 0xff;
	buffer[3] = input & 0xff;
	return output;
}

static uint32_t uint32FromNetwork(uint32_t value) {
	uint32_t ret = 0;
	unsigned char* input = (unsigned char*)&value;
	for (int i = 0; i < 4; i++) {
		ret += ret * 256 + input[i];
	}
	return ret;
}


bool ClientConnection::SendBuffer(void * pBuffer, int wSendSize) {
	if(!m_connection) {
		return false;
	}
	m_connection->sendData((char*)pBuffer, wSendSize);
	return true;
}

bool ClientConnection::SendData(int8_t wMainCmdID, int8_t wSubCmdID, void* pData, int wDataSize)
{
	CMD_Head head = {};
	head.CommandInfo.wMainCmdID = wMainCmdID;
	head.CommandInfo.wSubCmdID = wSubCmdID;
	head.CmdInfo.wDataSize = uint32ToNetwork(sizeof(CMD_Head) + wDataSize);

	SendBuffer(&head,sizeof(head));
	SendBuffer(pData, wDataSize);
	return true;
}

bool ClientConnection::SendData(int8_t wMainCmdID, int8_t wSubCmdID)
{
	CMD_Head head = {};
	head.CommandInfo.wMainCmdID=wMainCmdID;
	head.CommandInfo.wSubCmdID=wSubCmdID;
	head.CmdInfo.wDataSize = uint32ToNetwork(sizeof(CMD_Head));
	return SendBuffer(&head, sizeof(CMD_Head));
}



void ClientConnection::init(Service* service, std::string ip, int port )
{
	m_userData = NULL;
	m_handler = NULL;
	m_service = service;
	m_connection = new Connection(m_service);
	m_connection->setHandler(this);
	m_connection->connect(ip, port);
	m_service->setHandler(this);
	m_ip = ip;
	m_port = port;
	m_connected = false;
}

void ClientConnection::init(Service* service, Connection* conn) {
	m_userData = NULL;
	m_handler = NULL;
	m_service = service;
	m_connection = conn;
	m_connection->setHandler(this);
	m_connected = false;
}

void ClientConnection::onClose( Connection* connection)
{
	m_connection = NULL;
	m_connected = false;
	m_handler->onClientDisconnected(this);
}

void ClientConnection::handleCommand(std::string cmd, void * data)
{
	if (cmd == "sendData") {
		DBConnectionCmd* dbCmd = (DBConnectionCmd*)data;
		this->SendData((uint8_t)dbCmd->intAgrs2, (uint8_t)dbCmd->intArgs3, dbCmd->dataArgs, dbCmd->intArgs1);

		if (dbCmd->intArgs1) {
			delete  dbCmd->dataArgs;
		}
	}
}

void ClientConnection::onConnected( Connection* conn)
{
	m_connected = true;
	this->SendData(0, 1);

	if(this->m_handler) {
		this->m_handler->onClientConnected(this);
	}
}

void ClientConnection::onData( Connection* conn )
{
	for (;;) {
		int lenData = (int)conn->getBufferLen();
		if (lenData < sizeof(CMD_Head)) {
			return;
		}

		CMD_Head* cmdHead = (CMD_Head*)conn->getBuffer(sizeof(CMD_Head));
		int totalDataLen = uint32FromNetwork(cmdHead->CmdInfo.wDataSize);

		if (lenData < totalDataLen) {
			return;
		}

		unsigned char* dataBuf = (unsigned char*)conn->getBuffer(totalDataLen);
		this->onCmdHead((CMD_Head*)dataBuf);
		conn->removeBuffer(totalDataLen);
	}
}

void ClientConnection::onCmdHead( CMD_Head* header )
{
	
	if(header->CommandInfo.wMainCmdID == MDM_KN_COMMAND) {
		//this->SendData(0, 1);
		return;
	}

	if(this->m_handler) {
		this->m_handler->onClientData(this, header->CommandInfo.wMainCmdID,
			                      header->CommandInfo.wSubCmdID,
								  (unsigned char*)header + sizeof(CMD_Head),
								  uint32FromNetwork(header->CmdInfo.wDataSize) - sizeof(CMD_Head));
	}

}



void ClientConnection::setHandler( ClientConnectionHandler* handler )
{
	m_handler = handler;
}

void ClientConnection::sendDBData( int mainCmd, int subCmd, void* data, int len )
{
	if(!len) {
		return;
	}

	DBConnectionCmd* dbCmd = new DBConnectionCmd;
	dbCmd->dataArgs = len ? new char[len] : nullptr;
	dbCmd->intArgs1 = len;
	dbCmd->intAgrs2 = mainCmd;
	dbCmd->intArgs3 = subCmd;
	memcpy(dbCmd->dataArgs, data, len);
	m_service->sendCommand("sendData", dbCmd);
}

void ClientConnection::close()
{
	if(m_connection) {
		m_connection->close();
		m_connection = NULL;
	}
	m_service->stop();
	delete m_service;
	delete this;
}

void ClientConnection::setUserData( void* userData )
{
	m_userData = userData;
}

void* ClientConnection::getUserData()
{
	return m_userData;
}
